package com.falcon.mojo;

import com.falcon.domain.DependencyNode;
import com.falcon.util.PathUtil;
import com.falcon.util.PomUtil;
import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/** 设计思想:
     1> merge-pom: 在 clean 阶段执行，做两件事: 备份原来的pom、合并子模块的依赖到原 pom 中
     2> merge-source: 在 compile 前执行，添加子模块的资源目录到编译环境中: src/main/java, src/main/resources 四个目录
     3> restore-pom: 在 install 后执行执行，恢复原来的 pom 文件
    操作步骤: clean 和 install 必须分开执行，因为 clean 阶段会改变 pom。同时执行时，compile
     1> 先执行 mvn clean : 备份原 pom，并且合并子模块中的依赖到原pom，实现原pom的替换
     2) 再执行 mvn install : 添加子模块的源码目录、打包、install，然后恢复 原 pom
 * */
public abstract class AbsMojo extends AbstractMojo {

    /** 项目 */
    @Parameter(readonly = true, defaultValue = "${project}")
    protected MavenProject project;

    /** includeModules 生效则只合并 includeModules 配置的模块，否则合并所有子模块 */
    @Parameter(property = "enableIncludeModules")
    protected boolean enableIncludeModules;

    /** 打包的模块儿 */
    @Parameter(property = "includeModules")
    protected File[] includeModules;

    protected List<DependencyNode> getNeedAddDependencies(File[] modules) {
        // 获取所有模块的依赖
        Set<DependencyNode> allModuleDependencyList = new LinkedHashSet<DependencyNode>();
        for (File subModule : modules) {
            String subPom = PathUtil.getSubPomPath(subModule.getAbsolutePath());
            List<DependencyNode> dependencyList = PomUtil.getDependencies(subPom);
            allModuleDependencyList.addAll(dependencyList);
        }

        // 当前 pom 的坐标
        DependencyNode currentDependency = new DependencyNode(this.project.getGroupId(), this.project.getArtifactId());

        // 当前 pom 的依赖列表
        Set<DependencyNode> currentDependencies = new LinkedHashSet<DependencyNode>();
        for (Dependency dependency : this.project.getDependencies()) {
            currentDependencies.add(new DependencyNode(dependency.getGroupId(), dependency.getArtifactId()));
        }

        // 获取需要添加的依赖列表
        List<DependencyNode> newDependencyList = new ArrayList<DependencyNode>();
        for (DependencyNode dependencyNode : allModuleDependencyList) {
            if (!currentDependencies.contains(dependencyNode) && !currentDependency.equals(dependencyNode)) {
                newDependencyList.add(dependencyNode);
            }
        }
        return newDependencyList;
    }

    protected List<DependencyNode> getDependencies(File[] modules) {
        // 获取所有模块的依赖
        Set<DependencyNode> allModuleDependencyList = new LinkedHashSet<DependencyNode>();
        for (File subModule : modules) {
            String subPom = PathUtil.getSubPomPath(subModule.getAbsolutePath());
            List<DependencyNode> dependencyList = PomUtil.getDependencies(subPom);
            allModuleDependencyList.addAll(dependencyList);
        }

        // 当前 pom 的坐标
        DependencyNode currentDependency = new DependencyNode(this.project.getGroupId(), this.project.getArtifactId());

        // 当前 pom 的依赖列表
        Set<DependencyNode> currentDependencies = new LinkedHashSet<DependencyNode>();
        for (Dependency dependency : this.project.getDependencies()) {
            currentDependencies.add(new DependencyNode(dependency.getGroupId(), dependency.getArtifactId()));
        }

        // 获取需要添加的依赖列表
        List<DependencyNode> newDependencyList = new ArrayList<DependencyNode>();
        for (DependencyNode dependencyNode : allModuleDependencyList) {
            if (!currentDependency.equals(dependencyNode)) {
                newDependencyList.add(dependencyNode);
            }        }
        return newDependencyList;
    }

    // 获取所有的子模块
    protected File[] getSubModules() {
       final List<String> ignoreModules = new ArrayList<String>(){};
        ignoreModules.add("target");
        ignoreModules.add("src");

        return project.getBasedir().listFiles(new FileFilter() {
            public boolean accept(File f) {
                return !ignoreModules.contains(f.getName()) && f.isDirectory();
            }
        });
    }

    protected String checkTargetDir() {
        String targetDirPath = PathUtil.getTargetDir(this.project);
        File targetDir = new File(targetDirPath);
        if (!targetDir.exists()) {
            targetDir.mkdir();
        }
        return targetDirPath;
    }

}
